package objects;

import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.Arrays;
import objects.fields.BooleanVariable;
import objects.fields.IntegerVariable;
import objects.fields.ObjectArray;
import objects.fields.StringVariable;
import objects.slots.ArraySlot;
import objects.visualization.Block;
import objects.visualization.ListBlock;
import objects.visualization.TextBlock;

public abstract class DataObject {
	public static final GruClass classClass = new GruClass( new GruClass( null ) );
	public static final GruClass objectClass = new GruClass( new GruClass( new GruObject() ) );
	public static final GruClass fieldClass = new GruClass( new Field() );
	public static final GruClass methodClass = new GruClass( new Method() );
	public static final GruClass moduleClass = new GruClass( new Module() );
	public static final GruClass booleanClass = new GruClass( new BooleanVariable( false ) );
	public static final GruClass integerClass = new GruClass( new IntegerVariable( 0 ) );
	public static final GruClass arrayClass = new GruClass( new ObjectArray( new DataObject[ 0 ] ) );
	public static final GruClass stringClass = new GruClass( new StringVariable() );
	public static final AddressedObject nullObject = new AddressedObject();
	
	public static final GruClass[] nativeClasses = {	classClass, fieldClass, methodClass, moduleClass, booleanClass, integerClass, arrayClass, stringClass, objectClass };
	public static final GruClass[] addressedObjectClasses = { classClass, fieldClass, methodClass, moduleClass, objectClass };

	
	public static ArrayList<AddressedObject> objects = new ArrayList<AddressedObject>();

	public GruClass gruClass;
	public static int lastNum;
	
	public boolean isAddressed() {
		return false;
	}

	
	public DataObject readValue( RandomAccessFile file ) throws IOException {
		return null;
	}
	
	public void writeValue( RandomAccessFile file ) throws IOException {
	}

	public DataObject newObject() {
		return null;
	}
	
	public GruObject toGruObject() {
		return null;
	}

	public GruClass toGruClass() {
		return null;
	}
	
	public int toInteger() {
		return 0;
	}
	
	public ObjectArray toArray() {
		return null;
	}
	
	public String toCode( String indent ) {
		return "";
	}
	
	public Block toModuleBlock( int indent ) {
		return null;
	}
	
	public void select() {
	}

	
	

	public static RandomAccessFile file;
	public static boolean read;
	
	public void io( ) throws IOException {
	}
	
	public static <E extends AddressedObject> E objectIO( E object ) throws IOException {
		if( read ) {
			return (E) objects.get( file.readInt() );
		} else {
			file.writeInt( object.num );
			return object;
		}
	}
	
	public static <E extends AddressedObject> void listIO( ArrayList<E> list ) throws IOException {
		if( read ) {
			int quantity = file.readInt();
			for( int n = 0; n < quantity; n++ ) {
				list.add( (E) objects.get( file.readInt() ) );
			}
		} else {
			file.writeInt( list.size() );
			for( E object : list ) {
				file.writeInt( object.num );
			}
		}
	}
	
	public static DataObject[] arrayIO( DataObject[] array, int size ) throws IOException {
		if( read ) {
			array = new DataObject[ size ];
			for( int n = 0; n < size; n++ ) {
				int objNum = file.readInt();
				if( objNum < 0 ) {
					array[ n ] = objects.get( objNum ).toGruClass().nativeClass.readValue( file );
				} else {
					array[ n ] = objects.get( objNum );
					break;
				}
			}
		} else {
			for( DataObject element : array ) {
				if( !element.isAddressed() ) {
					file.writeInt( -element.gruClass.num );
				}
				element.writeValue( file );
			}
		}
		return array;
	}

	public static String stringIO( String string ) throws IOException {
		if( read ) {
			return file.readUTF();
		} else {
			file.writeUTF( string );
			return string;
		}
	}
	
	public static boolean booleanIO( boolean value ) throws IOException {
		if( read ) {
			return file.readBoolean();
		} else {
			file.writeBoolean( value );
			return value;
		}
	}
	

	
	
	public static void loadChunk() {
		try {
			read = true;
			file = new RandomAccessFile( "main.gru", "r" );
			
			AddressedObject.objects.clear();
			AddressedObject.objects.addAll( Arrays.asList( nativeClasses ) );
			
			for( GruClass nativeClass : DataObject.addressedObjectClasses ) {
				int classesQuantity = file.readInt();
				for( int n = 0; n < classesQuantity; n++ ) {
					DataObject object = nativeClass.nativeClass.newObject();
					object.gruClass = nativeClass;
					nativeClass.classObjects.add( (AddressedObject) object );
					AddressedObject.objects.add( (AddressedObject) object );
				}
			}
			
			for( DataObject object : AddressedObject.objects ) {
				object.io();
			}
			
			DataObject.file.close();
		} catch ( IOException ex ) {
			int a = 0;
		}
	}

	public static void saveChunk( String fileName ) {
	}	
}
